package hl.demosample.app.weight.downloadpicture;

import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.os.Environment;
import android.text.TextUtils;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;

import static android.os.Environment.MEDIA_MOUNTED;

public class FileUtils {
    private static final String JPEG_FILE_PREFIX = "img";
    private static final String JPEG_FILE_SUFFIX = ".jpg";

    private static final String ROOTFLODER = "DemoSample";

    // 判断SD卡是否存在
    public static boolean isSDCardExists() {
        String status = Environment.getExternalStorageState();
        return status.equals(Environment.MEDIA_MOUNTED);
    }

    // 读取公共目录的方法，该方法定义了该app文件保存根路径，请根据需要建立下级目录。非常感谢。
    public static String getAppFloderString() {
        File destDir = new File(Environment.getExternalStorageDirectory() + File.separator + ROOTFLODER);
        if (!destDir.exists()) {
            destDir.mkdirs();
        }
        return Environment.getExternalStorageDirectory() + File.separator + ROOTFLODER + File.separator;
    }

    // 判断路径是否存在，如不存在将会创建路径
    public static boolean isFolderExists(String strFolder) {
        File file = new File(strFolder);
        if (!file.exists()) {
            return file.mkdirs();
        }
        return true;
    }

    // 判断文件是否存在，如不存在将会创建文件
    public static boolean isFileExists(String strFile, boolean isCreate) throws IOException {
        File file = new File(strFile);
        if (!file.exists()) {
            if (isCreate) {
                String parentDirPath = strFile.substring(0, strFile.lastIndexOf(File.separator) + 1);
                File parentDir = new File(parentDirPath);
                if (!parentDir.exists()) {
                    boolean flag = parentDir.mkdirs();
                }
                return file.createNewFile();
            } else {
                return false;
            }
        }
        return true;
    }

    // 判断SD卡上的文件是否存在
    public static boolean isFileExists(String strFile) {
        File file = new File(strFile);
        return file.exists();
    }

    // 删除文件方法
    public static boolean deleteFile(String strFile) {
        File file = new File(strFile);
        return file.delete();
    }

    // 将输入流写入文件方法
    public static void writeFile(InputStream input, String file) throws Exception {
        OutputStream output = new FileOutputStream(file);
        byte[] buffer = new byte[4 * 1024];
        int len = -1;
        while ((len = input.read(buffer)) != -1) {
            output.write(buffer, 0, len);
        }
        output.flush();
        output.close();
    }

    // 对象写入文件方法
    public static void writeFile(Object o, String file) throws Exception {
        ObjectOutputStream w = new ObjectOutputStream(new FileOutputStream(file));
        String object = CommonUtils.objectToString(o);
        w.writeObject(object);
        w.flush();
        w.close();
    }

    // 从文件读取对象方法
    public static Object readFile(String file) throws Exception {
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
        Object o = in.readObject();
        in.close();
        return CommonUtils.stringToObjcet((String) o);
    }

    /**
     * 删除临时保存的文件
     *
     * @param filePath
     */
    public static void deleteSaveFile(String filePath) {
        try {//小米系统sd卡问题
            File file = new File(filePath);
            if (file.isDirectory()) {
                File files[] = file.listFiles();
                for (int i = 0; i < files.length; i++) {
                    files[i].delete();
                }
            } else {
                file.delete();
            }
        } catch (RuntimeException e) {

        } catch (Exception e) {
        }
    }

    //判断文件是否存在
    public static boolean isFileIsExists(String strFile) {
        try {
            File f = new File(strFile);
            if (!f.exists()) {
                return false;
            }
        } catch (Exception e) {
            return false;
        }
        return true;
    }

    /**
     * @param fileDir  文件目录
     * @param fileType 后缀名
     * @return 特定目录下的所有后缀名为fileType的文件列表
     */
    public static List<String> getFiles(File fileDir, String fileType) throws Exception {
        List<String> lfile = new ArrayList<String>();
        File[] fs = fileDir.listFiles();
        for (File f : fs) {
            if (f.isFile()) {
                if (fileType
                        .equals(f.getName().substring(
                                f.getName().lastIndexOf(".") + 1,
                                f.getName().length())))
                    lfile.add(f.getName());
            }
        }
        return lfile;
    }

    public static String getLoadPatchName(File fileDir, String fileType, String versionCode) throws Exception {
        List<String> files = getFiles(fileDir, fileType);
        int maxPatchVersion = 0;
        for (String name : files) {
            if (name.startsWith(versionCode + "_")) {
                int patchVersion = Integer.valueOf(name.substring(name.indexOf("_") + 1, name.indexOf(".")));
                maxPatchVersion = Math.max(maxPatchVersion, patchVersion);
            }
        }
        return String.valueOf(maxPatchVersion);
    }

    @TargetApi(Build.VERSION_CODES.FROYO)
    public static File createTmpFile(Context context) throws IOException {
        File dir;
        if (TextUtils.equals(Environment.getExternalStorageState(), Environment.MEDIA_MOUNTED)) {
            dir = new File(Environment.getExternalStorageDirectory() + File.separator + ROOTFLODER+"/Camera");
            if (!dir.exists()) {
                dir.mkdirs();
            }
        } else {
            dir = getCacheDirectory(context, true);
        }
        return File.createTempFile(JPEG_FILE_PREFIX, JPEG_FILE_SUFFIX, dir);
    }

    /**
     * Returns application cache directory. Cache directory will be created on SD card
     * <i>("/Android/data/[app_package_name]/cache")</i> (if card is mounted and app has appropriate permission) or
     * on device's file system depending incoming parameters.
     *
     * @param context        Application context
     * @param preferExternal Whether prefer external location for cache
     * @return Cache {@link File directory}.<br />
     * <b>NOTE:</b> Can be null in some unpredictable cases (if SD card is unmounted and
     * {@link Context#getCacheDir() Context.getCacheDir()} returns null).
     */
    public static File getCacheDirectory(Context context, boolean preferExternal) {
        File appCacheDir = null;
        String externalStorageState;
        try {
            externalStorageState = Environment.getExternalStorageState();
        } catch (NullPointerException e) {
            externalStorageState = "";
        } catch (IncompatibleClassChangeError e) {
            externalStorageState = "";
        }
        if (preferExternal && MEDIA_MOUNTED.equals(externalStorageState)) {
            appCacheDir = getExternalCacheDir(context);
        }
        if (appCacheDir == null) {
            appCacheDir = context.getCacheDir();
        }
        if (appCacheDir == null) {
            String cacheDirPath = context.getFilesDir().getPath() + context.getPackageName() + "/cache/";
            appCacheDir = new File(cacheDirPath);
        }
        return appCacheDir;
    }


    private static File getExternalCacheDir(Context context) {
        File dataDir = new File(new File(Environment.getExternalStorageDirectory(), "Android"), "data");
        File appCacheDir = new File(new File(dataDir, context.getPackageName()), "cache");
        if (!appCacheDir.exists()) {
            if (!appCacheDir.mkdirs()) {
                return null;
            }
            try {
                new File(appCacheDir, ".nomedia").createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return appCacheDir;
    }

    /**
     * 压缩指定路径的图片，并得到图片对象
     *
     * @param path bitmap source path
     * @return Bitmap {@link Bitmap}
     */
    public static Bitmap compressBitmap(String path, int width, int height) {
        final BitmapFactory.Options options = new BitmapFactory.Options();
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, options);
        options.inSampleSize = calculateInSampleSize(options, 1280, 960);
        options.inJustDecodeBounds = false;
        return cQuality(BitmapFactory.decodeFile(path, options));
    }

    /**
     * calculate the bitmap sampleSize
     *
     * @param options
     * @return
     */
    public static int calculateInSampleSize(BitmapFactory.Options options, int rqsW, int rqsH) {
        final int height = options.outHeight;
        final int width = options.outWidth;
        int inSampleSize = 1;
        if (rqsW == 0 || rqsH == 0) return 1;
        if (height > rqsH || width > rqsW) {
            final int heightRatio = Math.round((float) height / (float) rqsH);
            final int widthRatio = Math.round((float) width / (float) rqsW);
            inSampleSize = heightRatio < widthRatio ? heightRatio : widthRatio;
        }
        return inSampleSize;
    }

    /**
     * 根据bitmap压缩图片质量
     *
     * @param bitmap 未压缩的bitmap
     * @return 压缩后的bitmap
     */
    public static Bitmap cQuality(Bitmap bitmap) {
        ByteArrayOutputStream bOut = new ByteArrayOutputStream();
        int beginRate = 100;
        //第一个参数 ：图片格式 ，第二个参数： 图片质量，100为最高，0为最差  ，第三个参数：保存压缩后的数据的流
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bOut);
        while (bOut.toByteArray().length / 1024 > 100 && beginRate > 0) {  //如果压缩后大于100Kb，则提高压缩率，重新压缩
            beginRate -= 10;
            bOut.reset();
            bitmap.compress(Bitmap.CompressFormat.JPEG, beginRate, bOut);
        }
        ByteArrayInputStream bInt = new ByteArrayInputStream(bOut.toByteArray());
        Bitmap newBitmap = BitmapFactory.decodeStream(bInt);
        saveFile(newBitmap);
        if (newBitmap != null) {
            return newBitmap;
        } else {
            return bitmap;
        }
    }
    /**
     * 保存临时文件
     *
     * @param path
     */
    static String ORIGINAL_HOME_PATH;
    private static void saveFile(Bitmap bitmap) {
        if (FileUtils.isSDCardExists()) {
            ORIGINAL_HOME_PATH = FileUtils.getAppFloderString() + "originalImage";
            FileUtils.isFolderExists(ORIGINAL_HOME_PATH);
        }
        try {
            String filePath = ORIGINAL_HOME_PATH + File.separator + System.currentTimeMillis() + ".jpg";
            FileOutputStream fout = new FileOutputStream(filePath);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 100, fout);
            if (bitmap != null && !bitmap.isRecycled()) {
                bitmap.recycle();
            }
            fout.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }


    public static final boolean deleteDir(String dir) {
        if (dir == null) {
            return false;
        }
        return deleteDir(new File(dir));

    }

    public static final boolean deleteDir(File file) {
        if (file == null || (!file.exists())) {
            return false;
        }
        if (file.isFile()) {
            safeDeleteFile(file);
        } else if (file.isDirectory()) {
            File[] files = file.listFiles();
            if (files != null) {
                for (File subFile : files) {
                    deleteDir(subFile);
                }
                safeDeleteFile(file);
            }
        }
        return true;
    }

    public static final boolean safeDeleteFile(File file) {
        if (file == null) {
            return true;
        }
        if (file.exists()) {
            boolean deleted = file.delete();
            if (!deleted) {
                file.deleteOnExit();
            }
            return deleted;
        }
        return true;
    }

    public static File getAppVideoADPathFile(){
        String filePath = FileUtils.getAppFloderString() + "video";
        File dir = new File(filePath);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        return dir;
    }

    /**
     * 获取文件夹下的mp4文件集合
     * @param file
     * @return
     */
    public static ArrayList<String> getPathFilesName(File file) {
        ArrayList<String> filesName = new ArrayList<>();
        if(file.exists()){
            File[] files = file.listFiles();// 读取文件
            if(files!=null && files.length>0){
                for (int i = 0; i < files.length; i++) {
                    String fileName = files[i].getName();
//                String fileNameWithout = null;
                    if (fileName.endsWith(".mp4")) {
//                    fileNameWithout = fileName.substring(0,fileName.lastIndexOf(".")).toString();
                        filesName.add(fileName);
                    }
                }
            }
        }
        return filesName;
    }


    // 生成文件
    public static File makeFilePath(String fileName) {
        File file = null;
        String appFloderString = getAppFloderString();
        try{
            file =new File(appFloderString + fileName);
            if(!file.exists()) {
                file.createNewFile();
            }
        }catch(Exception e) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 复制文件
     * @param source 输入文件
     * @param target 输出文件
     */
    public static void copyFile(File source, File target) {
        FileInputStream fileInputStream = null;
        FileOutputStream fileOutputStream = null;
        try {
            fileInputStream = new FileInputStream(source);
            fileOutputStream = new FileOutputStream(target);
            byte[] buffer = new byte[1024];
            while (fileInputStream.read(buffer) > 0) {
                fileOutputStream.write(buffer);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                fileInputStream.close();
                fileOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }



    public FileUtils() {
        throw new UnsupportedOperationException("u can't instantiate me...");
    }

    /**
     * 获取可用的cache路径
     */
    public static File getAvailableCacheDir(Context context) {
        File file;
        if (isExternalStorageWritable()) {
            file = context.getExternalCacheDir();
        } else {
            file = context.getCacheDir();
        }
        return file;
    }

    private static boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        return Environment.MEDIA_MOUNTED.equals(state);
    }

    /**
     * Return the file by path.
     *
     * @param filePath The path of file.
     * @return the file
     */
    public static File getFileByPath(final String filePath) {
        return isSpace(filePath) ? null : new File(filePath);
    }

    /**
     * Create a directory if it doesn't exist, otherwise do nothing.
     *
     * @param file The file.
     * @return {@code true}: exists or creates successfully<br>{@code false}: otherwise
     */
    public static boolean createOrExistsDir(final File file) {
        return file != null && (file.exists() ? file.isDirectory() : file.mkdirs());
    }

    /**
     * Create a file if it doesn't exist, otherwise delete old file before creating.
     *
     * @param filePath The path of file.
     * @return {@code true}: success<br>{@code false}: fail
     */
    public static boolean createFileByDeleteOldFile(final String filePath) {
        return createFileByDeleteOldFile(getFileByPath(filePath));
    }

    /**
     * Create a file if it doesn't exist, otherwise delete old file before creating.
     *
     * @param file The file.
     * @return {@code true}: success<br>{@code false}: fail
     */
    public static boolean createFileByDeleteOldFile(final File file) {
        if (file == null) {
            return false;
        }
        // file exists and unsuccessfully delete then return false
        if (file.exists() && !file.delete()) {
            return false;
        }
        if (!createOrExistsDir(file.getParentFile())) {
            return false;
        }
        try {
            return file.createNewFile();
        } catch (IOException e) {
            e.printStackTrace();
            return false;
        }
    }

    private static boolean isSpace(final String s) {
        if (s == null) {
            return true;
        }
        for (int i = 0, len = s.length(); i < len; ++i) {
            if (!Character.isWhitespace(s.charAt(i))) {
                return false;
            }
        }
        return true;
    }

    /**
     * 根据文件路径拷贝文件
     * @param resourceFile 源文件
     * @param targetPath   目标路径（包含文件名和文件格式）
     * @return boolean 成功true、失败false
     */
    public static boolean copyFile(File resourceFile, String targetPath, String fileName) {
        boolean result = false;
        if (resourceFile == null || TextUtils.isEmpty(targetPath)) {
            return result;
        }
        File target = new File(targetPath);
        if (target.exists()) {
            target.delete(); // 已存在的话先删除
        } else {
            try {
                target.mkdirs();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        File targetFile = new File(targetPath.concat(fileName));
        if (targetFile.exists()) {
            targetFile.delete();
        } else {
            try {
                targetFile.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        FileChannel resourceChannel = null;
        FileChannel targetChannel = null;
        try {
            resourceChannel = new FileInputStream(resourceFile).getChannel();
            targetChannel = new FileOutputStream(targetFile).getChannel();
            resourceChannel.transferTo(0, resourceChannel.size(), targetChannel);
            result = true;
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            return result;
        } catch (IOException e) {
            e.printStackTrace();
            return result;
        }
        try {
            resourceChannel.close();
            targetChannel.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return result;
    }
}
